package cate.game.role.farm.forbidden;

import cate.common.table.d.*;
import cate.common.table.farm.forbidden.row.ForbiddenCombatRow;
import cate.common.table.farm.forbidden.row.ForbiddenRoomRow;
import cate.common.util.GameResult;
import cate.game.attr.FightAttr;
import cate.game.play.part.FightSide;
import cate.game.play.proce.play.PlayPO;
import cate.game.res.MixRes;
import cate.game.res.MixResAdder;
import cate.game.role.Role;
import cate.game.role.bag.hero.Hero;
import cate.game.role.farm.AbstractFarm;
import cate.game.role.farm.PlayTimes;
import cate.game.role.farm.forbidden.msg.ForbiddenAllMonsterResp;
import cate.game.role.farm.forbidden.msg.ForbiddenDataResp;
import cate.game.role.farm.forbidden.msg.ForbiddenDataUpdateResp;
import cate.game.role.farm.forbidden.msg.ForbiddenOneResp;
import cate.game.role.fight.FuncPosition;
import cate.game.role.fight.HeroGrid;
import cate.game.role.fight.Position;
import com.fasterxml.jackson.annotation.JsonIgnore;
import cp.solution.util.time.TimeKit;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import easy.java.practice.errorcode.EcResult;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.data.annotation.Transient;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import static cate.common.table.d.GDFunc.ADVENTURE;

@NoteClass("我的种族禁地副本数据")
public class MyForbiddenZone extends AbstractFarm {

    @NoteField(value = "所有禁地数据")
    public List<ForbiddenPO> fbList;

    @NoteField(value = "挑战次数")
    public PlayTimes playTimes;

    @NoteField(value = "已领取排行奖励的记录", detail = "Map<tid, 是否已领取>")
    private Map<Integer, Boolean> rankRewardMap;

    @NoteField(value = "当前/最近一次 所挑战的圣殿ID")
    public int curRoomId;

    @NoteField(value = "当前/最近一次 通关数更新时间")
    public long lastTime;

    @NoteField(value = "累计奖励")
    public MixRes accumulateReward;

    @NoteField(value = "自动战斗状态")
    public ForbiddenAutoStatus mopStatus;

    @Override
    public void initialize(Role role) {
        super.initialize(role);
        if (fbList == null) {
            fbList = new LinkedList<>();
        }
        if (playTimes == null) {
            playTimes = new PlayTimes();
        }
        playTimes.initialize();
        for (ForbiddenPO fb : fbList) {
            fb.initialize(role);
        }
        if (accumulateReward == null) {
            accumulateReward = new MixRes();
        }
        if (rankRewardMap == null) {
            rankRewardMap = new HashMap<>();
        }
        if (mopStatus == null) {
            mopStatus = new ForbiddenAutoStatus();
        }
    }

    @Override
    public void onEnter() {
        super.onEnter();
        checkOpen();
        noticeUpdate();
    }

    public boolean getOpen() {
        return this.open;
    }


    private void noticeUpdate() {
        role.sendNow(new ForbiddenDataResp(role));
        role.sendNow(new ForbiddenAllMonsterResp(role));
    }

    @Override
    public int getFuncId() {
        switch (curRoomId) {
            case 1:
                return GDFunc.FORBIDDEN_C1;
            case 2:
                return GDFunc.FORBIDDEN_C2;
            case 3:
                return GDFunc.FORBIDDEN_C3;
            case 4:
                return GDFunc.FORBIDDEN_C4;
            case 5:
                return GDFunc.FORBIDDEN_C5;
            case 6:
                return GDFunc.FORBIDDEN_C6;
            default:
                return GDFunc.FORBIDDEN_ZONE;
        }
    }

    @Override
    public void onAfterOpen() {
        noticeUpdate();
    }

    @Override
    public int getFightFuncId() {
        return GDFunc.FORBIDDEN_ZONE;
    }


    @Transient
    @JsonIgnore
    @Override
    public void onDaySpan(boolean silence) {
        playTimes.reset();
        noticeUpdate();
    }

    @Transient
    @JsonIgnore
    @Override
    public void onWeekSpan(boolean silence) {
        for (ForbiddenPO fb : fbList) {
            fb.reset();
        }
        noticeUpdate();
    }


    /**
     * 获取某类副本数据
     */

    @Transient
    @JsonIgnore
    public ForbiddenPO getFb(int roomId) {
        ForbiddenPO tar = null;
        for (ForbiddenPO fb : fbList) {
            if (fb.roomId == roomId) {
                tar = fb;
            }
        }
        if (tar == null) {
            tar = new ForbiddenPO();
            tar.roomId = roomId;
            tar.initialize(role);
            fbList.add(tar);
        }
        return tar;
    }


    /**
     * 获取本周通关总次数
     */
    @Transient
    @JsonIgnore
    public int getScoreTotal() {
        int scoreTotal = GD.INT_0;
        if (CollectionUtils.isNotEmpty(fbList)) {
            scoreTotal = fbList.stream().mapToInt(fb -> fb.score).sum();
        }
        return scoreTotal;
    }

    /**
     * 检查能否开始挑战或者扫荡
     */
    private GameResult<ForbiddenPO> challengeCheck(int roomId, int combatNum, boolean mop, boolean auto) {
        GameResult<ForbiddenPO> r = new GameResult<>();
        if (!isOpen()) {
            return r.fail("功能未开启");
        }
        if (fighting) {
            return r.fail("当前战斗未结束");
        }
        ForbiddenRoomRow roomTpl = role.getGame().table.forbidden.room.get(roomId);
        if (roomTpl == null) {
            return r.fail("非法类型");
        }
        int day = TimeKit.dayOfWeekCn();
        if (!roomTpl.openDays.contains(day)) {
            return r.fail("未到开放时间");
        }
        ForbiddenCombatRow combatTpl = role.getGame().table.forbidden.combat.find(roomId, combatNum);
        if (combatTpl == null) {
            return r.fail("模板表中找不到该关卡");
        }
        ForbiddenPO fb = getFb(roomId);
        if (fb == null) {
            return r.fail("类型异常");
        }

        if (!mop && !auto) {
            // 普通挑战模式
            // combatNum 只应该等于 combatNumPass+1
            if (combatNum <= fb.roundPass) {
                return r.fail("你已通过该副本，直接扫荡即可");
            }
            if (combatNum > fb.roundPass + 1) {
                return r.fail("请先通过前一个关卡");
            }
        } else if (mop) {
            // 扫荡模式
            if (combatNum > fb.roundPass) {
                return r.fail("尚未通过该副本，请先挑战，然后再扫荡");
            }
        } else if (mop && auto && fb.roundPass < 1) {
            return r.fail("当前无可扫荡关卡");
        }

        GameResult<Void> checkRes = this.playTimes.available(role, getFightFuncId());
        if (!checkRes.ok()) {
            return r.fail(checkRes);
        }
        r.data = fb;
        return r.success();
    }

    /**
     * 挑战或扫荡指定关卡入口
     *
     * @param roomId    圣殿ID(类型)
     * @param combatNum 第几关（从1开始）
     * @param mop       是否扫荡
     */
    public GameResult<Void> challenge(int roomId, int combatNum, boolean mop, boolean auto) {
        GameResult<Void> r = new GameResult<>();
        GameResult<ForbiddenPO> challengeRes = challengeCheck(roomId, combatNum, mop, auto);
        if (!challengeRes.ok()) {
            return r.fail(challengeRes);
        }
        ForbiddenPO fb = challengeRes.data;
        ForbiddenCombatRow combatTpl = role.getGame().table.forbidden.combat.find(roomId, combatNum);
        if (mop) {
            r = mop(fb, combatTpl, auto);
        } else {
            r = challenge(roomId, combatNum, combatTpl, auto);
        }
        return r;
    }

    /**
     * 挑战逻辑
     */
    public GameResult<Void> challenge(int roomId, int combatNum, ForbiddenCombatRow tpl, boolean auto) {
        GameResult<Void> r = new GameResult<>();
        this.curRoomId = roomId;

        if (auto && role.getBase().level < GDForbidden.EASY_FIGHT_LEVEL_REQUIRE) {
            return r.fail("等级不足,{}级开启", GDForbidden.EASY_FIGHT_LEVEL_REQUIRE);
        }

        // 挑战模式
        ForbiddenRoom room = role.getGame().farm.local.forbidden.status.getRoom(roomId);
        Map<Integer, Integer> monsterMap = room.monsterMap;
        if (!monsterMap.containsKey(combatNum)) {
            return r.fail("不存在该关卡");
        }
        int insId = monsterMap.get(combatNum);
        if (insId == GDForbidden.UNDEFINE_VALUE) {
            return r.fail("不存在的怪物阵容");
        }
        String instanceIdStr = role.getGame().table.forbidden.monster.get(insId).monsterStr;

        EcResult<FightSide> fsr = role.getGame().fight.side.createFightSideByCode(GDFight.Team.B, instanceIdStr);

        if (fsr.data == null) {
            return r.fail("策划配置的一方阵容不存在 tpl.instanceId=" + instanceIdStr);
        }
        ForbiddenFTC context = new ForbiddenFTC(role, tpl, auto);
        context.playStory.level = tpl.id;

        //玩家阵容属性加成
        ForbiddenRoomRow roomRow = role.getGame().table.forbidden.room.get(roomId);

        checkPosition();

        Position position = role.getFight().getPosition(getFuncId());
        if (position == null) {
            return r.fail("挑战阵容不存在");
        }

        if (position.grids.stream().filter(grid -> {
            Hero hero = null;
            if (grid.origin == GDPosition.Origin.BAG) {
                hero = role.getBag().hero.getItem(grid.uid);
            }
            if (hero != null) {
                return hero.getTpl(role.getGame()).camp == tpl.campReq;
            }
            return false;
        }).count() < tpl.campNumReq) {
            return r.fail("上阵英雄不满足条件");
        }
        for (HeroGrid grid : position.grids) {
            Hero hero = null;
            if (grid.origin == GDPosition.Origin.BAG) {
                hero = role.getBag().hero.getItem(grid.uid);
            }
            if (hero == null) {
                continue;
            }
//            log.info("阵营:" + hero.getTpl(role.getGame()).camp);
            FightAttr attr = new FightAttr(roomRow.campAttrs.get(hero.getTpl(role.getGame()).camp - 1));
            context.param.sideA.attrAppend.addHeroAttr(hero.tid, attr);
        }
        // 自动扫荡不发录像 后台倍速播放
        if (auto) {
            context.needSend = false;
            context.playSpeed = GDFight.FAST_SPEED_RATE;
        }
        // 种族禁地大类型 sub填子类型
        context.funcId = getFuncId();
        context.playStory.subType = roomId;
        EcResult<PlayPO> fightRes = role.getGame().play.startByRole(role, context, fsr.data);
        if (!fightRes.ok()) {
            return r.fail(fightRes.message);
        }
        PlayPO play = fightRes.data;

        if (auto) {
            mopStatus.onChallenge(roomId, combatNum, play.startTime, play.endTime);
        }

        lastTime = System.currentTimeMillis();
        this.fighting = true;
        return r.success();
    }

    public void checkPosition() {
        if (role.getFight().funcPositions.get(getFuncId()) == null
                || role.getFight().funcPositions.get(getFuncId()).positions.isEmpty()) {
            Position position = role.getFight().getPosition(ADVENTURE);
            if (position != null) {
                FuncPosition funcPosition = new FuncPosition();
                funcPosition.init();
                funcPosition.funcId = getFuncId();
                funcPosition.positions.add(position.copy());
                role.getGame().fight.position.updatePosition(role, funcPosition);
            }
        }
    }

    /**
     * 扫荡逻辑
     */
    private GameResult<Void> mop(ForbiddenPO fb, ForbiddenCombatRow combatTpl, boolean auto) {
        // 扫荡模式
        if (!auto) {
            GameResult<Void> r = new GameResult<>();
            MixRes reward = new MixRes(combatTpl.rewardStr);
            reward.add(role, true, GDOperation.FORBIDDEN_MOP_REWARD);
            role.getGame().notice.dialogReward(role, new MixRes(combatTpl.rewardStr));
            playTimes.added();
            fb.addScore(combatTpl.mopScore,System.currentTimeMillis());
            role.sendNow(new ForbiddenOneResp(fb));
            return r.success();
        } else {
            return batchMop(fb);
        }
    }

    /**
     * 一键挑战 （根据历史最大通关扫荡本周未通关的关卡）(扫荡则至玩家最大关，一键战斗则自动战斗到失败)
     *
     * @param fb  fb
     * @return r
     */
    public GameResult<Void> batchMop(ForbiddenPO fb) {
        GameResult<Void> r = new GameResult<>();

        MixRes reward = new MixRes();

        if (fb.roundPass == 0) {
            return r.fail("没有可扫荡的关卡");
        }

        for (int combatNum = 1; combatNum <= fb.roundPass; combatNum++) {
            // 检测免费次数和余额
            if (!this.playTimes.checkFreeAndBalance(role, getFightFuncId()).ok()) {
                break;
            }
            ForbiddenCombatRow combatTpl = role.getGame().table.forbidden.combat.find(fb.roomId, combatNum);
            if (combatTpl == null) {
                break;
            }
            this.playTimes.added();
            fb.addScore(combatTpl.mopScore,System.currentTimeMillis());
            fb.roundPass = combatNum;
            reward.addList(new MixRes(combatTpl.rewardFirstStr));
        }

        this.curRoomId = fb.roomId;

        role.sendNow(new ForbiddenOneResp(fb));
        role.sendNow(new ForbiddenDataUpdateResp(role));

        new MixResAdder().setRes(reward).setOperation(GDOperation.FORBIDDEN_CHALLENGE).exe(role);
        role.getGame().notice.dialogReward(role, reward);
        return r.success();
    }

    /**
     * 元素圣殿调整关数信息
     * @param roomId r
     * @param roundPass r
     * @param passMax p
     * @return r
     */
    public GameResult<Void> gmOpenLevel(int roomId, int roundPass, int passMax) {
        GameResult<Void> r = new GameResult<>();
        if (!isOpen()) {
            return r.fail("功能未开启");
        }
        ForbiddenRoomRow roomTpl = role.getGame().table.forbidden.room.get(roomId);
        if (roomTpl == null) {
            return r.fail("非法类型");
        }
        ForbiddenPO fb = getFb(roomId);
        if (fb == null) {
            return r.fail("类型异常");
        }
        fb.passMax = passMax;
        fb.roundPass = roundPass;
        noticeUpdate();
        return r.success();
    }
}
